"""
绩效分析模块

计算和分析回测策略的绩效指标。

作者: AI Assistant
版本: 1.0.0
日期: 2025-01-06
"""

import pandas as pd
import numpy as np
from typing import Dict, List
import logging


class PerformanceAnalyzer:
    """
    绩效分析器
    
    计算回测策略的各项绩效指标，包括：
    - 收益率指标
    - 风险指标
    - 风险调整收益指标
    - 交易统计指标
    
    属性:
        initial_capital: 初始资金
        risk_free_rate: 无风险利率（默认3%）
    """
    
    def __init__(self, initial_capital: float, risk_free_rate: float = 0.03):
        """
        初始化绩效分析器
        
        参数:
            initial_capital: 初始资金
            risk_free_rate: 无风险利率，默认0.03（3%）
        """
        self.initial_capital = initial_capital
        self.risk_free_rate = risk_free_rate
        self.logger = logging.getLogger(__name__)
    
    def calculate_return_metrics(
        self,
        final_value: float,
        days: int
    ) -> Dict:
        """
        计算收益率指标
        
        参数:
            final_value: 最终资产价值
            days: 回测天数
            
        返回:
            Dict: 包含总收益率和年化收益率的字典
        """
        # 总收益率
        total_return = ((final_value - self.initial_capital) / self.initial_capital) * 100
        
        # 年化收益率
        years = days / 252  # 假设一年252个交易日
        if years > 0:
            annual_return = ((final_value / self.initial_capital) ** (1 / years) - 1) * 100
        else:
            annual_return = 0
        
        return {
            '总收益率': total_return,
            '年化收益率': annual_return,
        }
    
    def calculate_risk_metrics(self, equity_curve: pd.Series) -> Dict:
        """
        计算风险指标
        
        参数:
            equity_curve: 资金曲线（时间序列）
            
        返回:
            Dict: 包含最大回撤、波动率等风险指标
        """
        # 计算日收益率
        returns = equity_curve.pct_change().dropna()
        
        # 最大回撤
        running_max = equity_curve.expanding().max()
        drawdown = (equity_curve - running_max) / running_max * 100
        max_drawdown = drawdown.min()
        max_drawdown_date = drawdown.idxmin()
        
        # 波动率（年化）
        volatility = returns.std() * np.sqrt(252) * 100
        
        # 下行波动率（只考虑负收益）
        downside_returns = returns[returns < 0]
        downside_volatility = downside_returns.std() * np.sqrt(252) * 100 if len(downside_returns) > 0 else 0
        
        return {
            '最大回撤': max_drawdown,
            '最大回撤日期': max_drawdown_date,
            '波动率': volatility,
            '下行波动率': downside_volatility,
        }
    
    def calculate_risk_adjusted_return(
        self,
        annual_return: float,
        returns: pd.Series,
        downside_returns: pd.Series
    ) -> Dict:
        """
        计算风险调整收益指标
        
        参数:
            annual_return: 年化收益率
            returns: 日收益率序列
            downside_returns: 下行收益率序列
            
        返回:
            Dict: 包含夏普比率、索提诺比率等指标
        """
        # 夏普比率
        excess_returns = returns - self.risk_free_rate / 252
        sharpe_ratio = (
            np.sqrt(252) * excess_returns.mean() / returns.std()
            if returns.std() > 0 else 0
        )
        
        # 索提诺比率（只考虑下行风险）
        downside_std = downside_returns.std() * np.sqrt(252)
        sortino_ratio = (
            (annual_return / 100 - self.risk_free_rate) / downside_std
            if downside_std > 0 else 0
        )
        
        return {
            '夏普比率': sharpe_ratio,
            '索提诺比率': sortino_ratio,
        }
    
    def calculate_trade_metrics(self, trades: List[Dict]) -> Dict:
        """
        计算交易统计指标
        
        参数:
            trades: 交易记录列表
            
        返回:
            Dict: 包含胜率、盈亏比等交易指标
        """
        # 过滤出卖出交易
        sell_trades = [
            t for t in trades
            if t['类型'] in ['SELL', 'FORCE_CLOSE'] and '盈亏' in t
        ]
        
        if not sell_trades:
            return {
                '交易次数': 0,
                '胜率': 0,
                '盈亏比': 0,
                '平均盈利': 0,
                '平均亏损': 0,
                '最大单笔盈利': 0,
                '最大单笔亏损': 0,
            }
        
        # 分类交易
        winning_trades = [t for t in sell_trades if t['盈亏'] > 0]
        losing_trades = [t for t in sell_trades if t['盈亏'] <= 0]
        
        # 胜率
        win_rate = len(winning_trades) / len(sell_trades) * 100
        
        # 平均盈利和亏损
        avg_win = np.mean([t['盈亏'] for t in winning_trades]) if winning_trades else 0
        avg_loss = np.mean([abs(t['盈亏']) for t in losing_trades]) if losing_trades else 0
        
        # 盈亏比
        profit_loss_ratio = avg_win / avg_loss if avg_loss > 0 else 0
        
        # 最大单笔盈利和亏损
        max_win = max([t['盈亏'] for t in winning_trades]) if winning_trades else 0
        max_loss = min([t['盈亏'] for t in losing_trades]) if losing_trades else 0
        
        # 总盈利和总亏损
        total_profit = sum([t['盈亏'] for t in winning_trades])
        total_loss = sum([t['盈亏'] for t in losing_trades])
        
        return {
            '交易次数': len(sell_trades),
            '盈利次数': len(winning_trades),
            '亏损次数': len(losing_trades),
            '胜率': win_rate,
            '盈亏比': profit_loss_ratio,
            '平均盈利': avg_win,
            '平均亏损': avg_loss,
            '最大单笔盈利': max_win,
            '最大单笔亏损': max_loss,
            '总盈利': total_profit,
            '总亏损': total_loss,
        }
    
    def analyze(
        self,
        final_value: float,
        equity_curve: pd.Series,
        trades: List[Dict]
    ) -> Dict:
        """
        综合分析绩效
        
        参数:
            final_value: 最终资产价值
            equity_curve: 资金曲线
            trades: 交易记录列表
            
        返回:
            Dict: 包含所有绩效指标的字典
        """
        self.logger.info("开始计算绩效指标...")
        
        # 基础数据
        days = len(equity_curve)
        returns = equity_curve.pct_change().dropna()
        downside_returns = returns[returns < 0]
        
        # 计算各类指标
        return_metrics = self.calculate_return_metrics(final_value, days)
        risk_metrics = self.calculate_risk_metrics(equity_curve)
        risk_adj_metrics = self.calculate_risk_adjusted_return(
            return_metrics['年化收益率'],
            returns,
            downside_returns
        )
        trade_metrics = self.calculate_trade_metrics(trades)
        
        # 卡玛比率（收益回撤比）
        calmar_ratio = (
            abs(return_metrics['年化收益率'] / risk_metrics['最大回撤'])
            if risk_metrics['最大回撤'] != 0 else 0
        )
        
        # 合并所有指标
        result = {
            **return_metrics,
            **risk_metrics,
            **risk_adj_metrics,
            **trade_metrics,
            '卡玛比率': calmar_ratio,
            '初始资金': self.initial_capital,
            '最终资金': final_value,
            '回测天数': days,
            '回测年数': days / 252,
        }
        
        self.logger.info("绩效指标计算完成")
        return result

